#include "LecteurPhraseAvecTable.h"

#include <stdlib.h>
#include <iostream>
using namespace std;

////////////////////////////////////////////////////////////////////////////////
LecteurPhraseAvecTable::LecteurPhraseAvecTable(string nomFich) :
	ls(nomFich), ts() {
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::analyse() {
	programme();
	cout << "Syntaxe correcte." << endl;
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::programme() {
// <programme> ::= debut <seqInst> fin <EOF>

	sauterSymCour("debut");
	seqInst();
	sauterSymCour("fin");
	testerSymCour("<FINDEFICHIER>");
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::seqInst() {
// <seqIns> ::= <inst> ; { <inst> ; }

	do {
		inst();
		sauterSymCour(";");
	} while (ls.getSymCour()=="<VARIABLE>" || ls.getSymCour()=="si" 
                 || ls.getSymCour()=="tantque" || ls.getSymCour()=="repeter" 
                 || ls.getSymCour()=="lire"    || ls.getSymCour()=="ecrire" 
                 ||ls.getSymCour()=="pour");
	// tant que le symbole courant est un debut possible d'instruction...
}

///////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::inst() {
// <inst> ::= <affectation> | <instSi> | <instTq> | <instRepeter> | <instPour>

		          
        if(ls.getSymCour()=="<VARIABLE>")
        {
            affectation();
        } 
        
    	else if (ls.getSymCour()=="si"){
            instSi();
        } 
        
        else if(ls.getSymCour()=="tantque"){
            instTq();
        }
        
        else if(ls.getSymCour()=="repeter"){
            instRepeter();
        }  
        else if(ls.getSymCour()=="pour"){
            instPour();
        }
        else if(ls.getSymCour()=="lire"){
            instLire();
        }
        else if(ls.getSymCour()=="ecrire"){
            instEcrire();
        }
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::instSi(){
// si (<exBool> ) <seqInst> { sinonSi (<exBool>) <seqInst> } [sinon <seqInst>] finSi
    if (ls.getSymCour()=="si"){
        ls.suivant();
    }
    sauterSymCour("(");
    expBool();
    sauterSymCour(")");
    seqInst();
    while (ls.getSymCour()=="sinonsi"){
        sauterSymCour("sinonsi");
        sauterSymCour("(");
        expBool();
        sauterSymCour(")");
        seqInst();
    }
    if (ls.getSymCour()=="sinon")
    {
        sauterSymCour("sinon");
        seqInst();
    }
    sauterSymCour("finsi");
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::instTq(){ 
// tantque ( <expBool> ) <seqInst> fintantque
     if (ls.getSymCour()=="tantque"){
        ls.suivant();
    }
     sauterSymCour("(");
     expBool();
     sauterSymCour(")");
     seqInst();
     sauterSymCour("fintantque");     
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::instRepeter(){
// <instRepeter ::= repeter <seqInst> jusqua (<expBool>)   
    if (ls.getSymCour()=="repeter"){
        ls.suivant();
    }
    seqInst();
    sauterSymCour("jusqua");
    sauterSymCour("(");
    expBool();
    sauterSymCour(")");
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::instLire(){
// <instLire> ::= lire ( <variable> )  
    if (ls.getSymCour()=="lire"){
        ls.suivant();
    } 
    sauterSymCour("(");
    testerSymCour("<VARIABLE>"); //test pour etre sure d'avoir une variable et 
                                //en plus on a besoin de l'ajouter à la table des symbole
    ts.chercheAjoute((ls.getSymCour()));
    ls.suivant();
    sauterSymCour(")");
}    

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::instEcrire(){
// <instEcrire ::= ecrire( <expression> | <chaine> )
    if (ls.getSymCour()=="ecrire"){
        ls.suivant();
    }    
    sauterSymCour("(");
    if (ls.getSymCour()=="<ENTIER>" || ls.getSymCour()=="<VARIABLE>" || ls.getSymCour()=="-" || ls.getSymCour()=="non" || ls.getSymCour()=="("){
        expression();
    }
    else if (ls.getSymCour()=="<CHAINE>"){
        
        ts.chercheAjoute(ls.getSymCour());
        ls.suivant();
        //sauterSymCour("<CHAINE>"); 
        
    }
    else{
        (erreur("<instEcrire>"));
    }
    sauterSymCour(")");
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::instPour(){   
// <instPour ::= pour ( <affectaction> ; <expBool> ; <affectation> ) <seqInst> finpour
    if (ls.getSymCour()=="pour"){
        ls.suivant();
    }
    
    sauterSymCour("(");
    affectation();
    sauterSymCour(";");
    expBool();
    sauterSymCour(";");
    affectation();
    sauterSymCour(")");
    seqInst();
    sauterSymCour("finpour");
}


////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::affectation() {
// <affectation> ::= <variable> = ( <expression> | <Chaine>)

	//sauterSymCour("<VARIABLE>");
	testerSymCour("<VARIABLE>");        // on teste qu'il s'agit bien d'un VARIABLE
	ts.chercheAjoute(ls.getSymCour()); //Avant de l'ajouter
	ls.suivant();
	sauterSymCour("=");
        if(ls.getSymCour()=="<CHAINE>"){
              ts.chercheAjoute(ls.getSymCour());
              ls.suivant();
        }
        else{    
            expression();
        }
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::expression() {
// <expression> ::= <terme> { <opAdd> <terme> }
	terme();
	while (ls.getSymCour()=="+" || ls.getSymCour()=="-") {
		opAdd();
		terme();
	}
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::facteur() {
// <facteur> ::= <entier>  |  <variable>  |<opUnaire> <expBool> | (<expBool>)

	if (ls.getSymCour()=="<VARIABLE>" || ls.getSymCour()=="<ENTIER>") {
		ts.chercheAjoute(ls.getSymCour());
		ls.suivant();
	} else if (ls.getSymCour()=="-" ||ls.getSymCour()=="non") {
                opUnaire();
                expBool();
	} else if (ls.getSymCour()=="(") {
		ls.suivant();
		expBool();
		sauterSymCour(")");
	} else
		erreur("<facteur>");
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::relation(){
// <relation> ::=<expression> { <opRel> <expression> }
    expression();
    while (ls.getSymCour()=="==" || ls.getSymCour()=="!=" || ls.getSymCour()=="<" || ls.getSymCour()=="<=" || ls.getSymCour()==">" || ls.getSymCour()==">=")
    {
        opRel();
        expression();
    }
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::terme()
// <terme>::= <facteur> {<opMult> <facteur>} 
{
    facteur();    
    while(ls.getSymCour()=="*" || ls.getSymCour()=="/")
    {
        opMult();
        facteur();
    }    
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::op(){
// <op> ::= <relation> { <opEt> <relation>}    
    relation();
    while (ls.getSymCour() =="et")
    {        
        opBoolEt();
        relation();
    }   
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::expBool(){ 
// <expBool> ::= <op> { <opBoolou> <op>}
    op();    
    while (ls.getSymCour() =="ou" )
    {
        opBoolOu();
        op();
    }    
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::opBoolOu(){
// Ou
    if (ls.getSymCour()=="ou") 
    {
        ls.suivant();
    }
    else
    {
        erreur("<opOu>");
    }
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::opBoolEt(){
// Et
    
    if (ls.getSymCour()=="et")
    {
        ls.suivant();
    }
    else
    {
        erreur("<opEt>");
    }
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::opAdd()
// +|-    
{
    if (ls.getSymCour()=="+" || ls.getSymCour()=="-")
    {
        ls.suivant();
    }
    else
    {
        erreur("<opAdd>");
    }
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::opMult()
// *|/
{
    if (ls.getSymCour()=="*" || ls.getSymCour()=="/")
    {
        ls.suivant();
    }
    else
    {
        erreur("<opMult>");
    } 
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::opRel(){
// == | != | < | <= | > | >=
    if (ls.getSymCour()=="==" || ls.getSymCour()=="!=" || ls.getSymCour()=="<" || ls.getSymCour()=="<=" || ls.getSymCour()==">" || ls.getSymCour()==">=")
    {
        ls.suivant();
    }
    else
    {
        erreur("<opRel>");
    }
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::opUnaire(){
// - | non    
    if (ls.getSymCour()=="-" || ls.getSymCour()=="non")
    {
       ls.suivant(); 
    }
    else
    {
        erreur("<opUnaire>");
    }
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::testerSymCour(string ch) {
	if (ls.getSymCour() != ch) {
		cout << endl << "-------- Erreur ligne " << ls.getLigne()
				<< " - Colonne " << ls.getColonne() << endl << "   Attendu : "
				<< ch << endl << "   Trouve  : " << ls.getSymCour() << endl
				<< endl;
		exit(0); // plus tard, on levera une exception
	}
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::sauterSymCour(string ch) {
	testerSymCour(ch);
	ls.suivant();
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecTable::erreur(string mess) {
	cout << endl << "-------- Erreur ligne " << ls.getLigne() << " - Colonne "
			<< ls.getColonne() << endl << "   Attendu : " << mess << endl
			<< "   Trouve  : " << ls.getSymCour() << endl << endl;
	exit(0); // plus tard, on levera une exception
}
